﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using IssueVision.Data.Web;
using IssueVision.Common;
using MVVMPlugin;

namespace IssueVision.ViewModel
{
    [ExportPlugin(ViewModelTypes.MyProfileViewModel, PluginType.ViewModel)]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class MyProfileViewModel : ViewModelBase
    {
        #region "Private Data Members"
        private IIssueVisionModel _issueVisionModel;
        #endregion "Private Data Members"

        #region "Constructor"
        public MyProfileViewModel()
        {
            _issueVisionModel = PluginCatalogService.Container.GetExportedValue<IIssueVisionModel>();

            // set up event handling
            _issueVisionModel.GetCurrentUserComplete += _issueVisionModel_GetCurrentUserComplete;
            _issueVisionModel.GetSecurityQuestionsComplete += _issueVisionModel_GetSecurityQuestionsComplete;
            _issueVisionModel.SaveChangesComplete += _issueVisionModel_SaveChangesComplete;
            _issueVisionModel.PropertyChanged += _issueVisionModel_PropertyChanged;

            // load current user
            _issueVisionModel.GetCurrentUserAsync();
            // load security questions
            _issueVisionModel.GetSecurityQuestionsAsync();
        }
        #endregion "Constructor"

        #region "ICleanup interface implementation"
        public override void Cleanup()
        {
            if (_issueVisionModel != null)
            {
                // unregister all event handling
                _issueVisionModel.GetCurrentUserComplete -= _issueVisionModel_GetCurrentUserComplete;
                _issueVisionModel.GetSecurityQuestionsComplete -= _issueVisionModel_GetSecurityQuestionsComplete;
                _issueVisionModel.SaveChangesComplete -= _issueVisionModel_SaveChangesComplete;
                _issueVisionModel.PropertyChanged -= _issueVisionModel_PropertyChanged;
                _issueVisionModel = null;
            }
            // set properties back to null
            CurrentUser = null;
            SecurityQuestionEntries = null;
            // unregister any messages for this ViewModel
            base.Cleanup();
        }
        #endregion "ICleanup interface implementation"

        #region "Public Properties"

        private User _currentUser;

        public User CurrentUser
        {
            get { return _currentUser; }
            private set
            {
                if (!ReferenceEquals(_currentUser, value))
                {
                    _currentUser = value;
                    RaisePropertyChanged("CurrentUser");
                }
            }
        }

        private IEnumerable<SecurityQuestion> _securityQuestionEntries;

        public IEnumerable<SecurityQuestion> SecurityQuestionEntries
        {
            get { return _securityQuestionEntries; }
            private set
            {
                if (!ReferenceEquals(_securityQuestionEntries, value))
                {
                    _securityQuestionEntries = value;
                    RaisePropertyChanged("SecurityQuestionEntries");
                }
            }
        }

        #endregion "Public Properties"

        #region "Public Commands"

        private RelayCommand _submitChangeCommand;

        public RelayCommand SubmitChangeCommand
        {
            get
            {
                if (_submitChangeCommand == null)
                {
                    _submitChangeCommand = new RelayCommand(
                        OnSubmitChangeCommand,
                        () => (_issueVisionModel != null) && (_issueVisionModel.HasChanges));
                }
                return _submitChangeCommand;
            }
        }

        private void OnSubmitChangeCommand()
        {
            try
            {
                if (!_issueVisionModel.IsBusy)
                {
                    if (CurrentUser != null)
                    {
                        // this should trigger validation even if the following field is not changed and is null
                        if (string.IsNullOrWhiteSpace(CurrentUser.Password))
                            CurrentUser.Password = string.Empty;
                        if (string.IsNullOrWhiteSpace(CurrentUser.NewPassword))
                            CurrentUser.NewPassword = string.Empty;
                        if (string.IsNullOrWhiteSpace(CurrentUser.NewPasswordConfirmation))
                            CurrentUser.NewPasswordConfirmation = string.Empty;
                        if (string.IsNullOrWhiteSpace(CurrentUser.PasswordAnswer))
                            CurrentUser.PasswordAnswer = string.Empty;
                        if (string.IsNullOrWhiteSpace(CurrentUser.PasswordAnswerConfirmation))
                            CurrentUser.PasswordAnswerConfirmation = string.Empty;

                        if (CurrentUser.TryValidateProperty("Name") && CurrentUser.TryValidateProperty("FirstName")
                            && CurrentUser.TryValidateProperty("LastName") && CurrentUser.TryValidateProperty("Email")
                            && CurrentUser.TryValidateProperty("Password") && CurrentUser.TryValidateProperty("NewPassword")
                            && CurrentUser.TryValidateProperty("NewPasswordConfirmation") && CurrentUser.TryValidateProperty("PasswordQuestion")
                            && CurrentUser.TryValidateProperty("PasswordAnswer") && CurrentUser.TryValidateProperty("PasswordAnswerConfirmation")
                            && CurrentUser.TryValidateProperty("UserType"))
                        {
                            // change is not from User Maintenance screen
                            CurrentUser.IsUserMaintenance = false;
                            _issueVisionModel.SaveChangesAsync();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        private RelayCommand _cancelChangeCommand;

        public RelayCommand CancelChangeCommand
        {
            get
            {
                if (_cancelChangeCommand == null)
                {
                    _cancelChangeCommand = new RelayCommand(
                        OnCancelChangeCommand,
                        () => (_issueVisionModel != null) && (_issueVisionModel.HasChanges));
                }
                return _cancelChangeCommand;
            }
        }

        private void OnCancelChangeCommand()
        {
            try
            {
                if (!_issueVisionModel.IsBusy)
                {
                    // ask to confirm canceling the current user in edit
                    var dialogMessage = new DialogMessage(
                        this,
                        CommonResources.CancelAnyChangesMessageBoxText,
                        s =>
                        {
                            if (s == MessageBoxResult.OK)
                            {
                                // if confirmed, cancel any change to CurrentUser
                                _issueVisionModel.RejectChanges();
                            }
                        })
                            {
                                Button = MessageBoxButton.OKCancel,
                                Caption = CommonResources.ConfirmMessageBoxCaption
                            };

                    AppMessages.PleaseConfirmMessage.Send(dialogMessage);
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        #endregion "Public Commands"

        #region "Private Methods"

        private void _issueVisionModel_GetCurrentUserComplete(object sender, EntityResultsArgs<User> e)
        {
            if (!e.HasError)
            {
                if (e.Results.Count() == 1)
                {
                    var enumerator = e.Results.GetEnumerator();
                    enumerator.MoveNext();
                    CurrentUser = enumerator.Current;
                }
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        private void _issueVisionModel_GetSecurityQuestionsComplete(object sender, EntityResultsArgs<SecurityQuestion> e)
        {
            if (!e.HasError)
            {
                SecurityQuestionEntries = e.Results.OrderBy(g => g.PasswordQuestion);
                // raise property changed for CurrentUser to reflect changes with SecurityQuestionEntries
                RaisePropertyChanged("CurrentUser");
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        private void _issueVisionModel_SaveChangesComplete(object sender, SubmitOperationEventArgs e)
        {
            if (!e.HasError)
            {
                // load the current user again
                _issueVisionModel.GetCurrentUserAsync();
                // notify user of my profile saved successfully
                var dialogMessage = new DialogMessage(
                    this,
                    CommonResources.MyProfileSavedText,
                    null)
                    {
                        Button = MessageBoxButton.OK,
                        Caption = CommonResources.MyProfileSavedCaption
                    };

                AppMessages.StatusUpdateMessage.Send(dialogMessage);
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        private void _issueVisionModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName.Equals("HasChanges"))
            {
                SubmitChangeCommand.RaiseCanExecuteChanged();
                CancelChangeCommand.RaiseCanExecuteChanged();
            }
        }

        #endregion "Private Methods"
    }
}
